package io.github.wanggit.antrpc.console.service.impl;

import io.github.wanggit.antrpc.commons.bean.ConfigItemData;
import io.github.wanggit.antrpc.commons.constants.ConstantValues;
import io.github.wanggit.antrpc.commons.utils.JsonUtils;
import io.github.wanggit.antrpc.console.service.ConfigService;
import io.github.wanggit.antrpc.console.service.dto.NodeDataDTO;
import io.github.wanggit.antrpc.console.web.vo.ConfigVO;
import io.github.wanggit.antrpc.console.web.vo.Result;
import io.github.wanggit.antrpc.console.zookeeper.IConfigContainer;
import io.github.wanggit.antrpc.console.zookeeper.ISubscribeConfigContainer;
import io.github.wanggit.antrpc.console.zookeeper.IZkNodeOperator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ConfigServiceImpl implements ConfigService {

    @Autowired private IConfigContainer configContainer;

    @Autowired private ISubscribeConfigContainer subscribeConfigContainer;

    @Autowired private IZkNodeOperator zkNodeOperator;

    @Override
    public void saveOrUpdate(ConfigVO configVO) {}

    @Override
    public void delete(ConfigVO configVO) {}

    @Override
    public List<String> findAllEnvs(String keyword) {
        return configContainer.findAllEnvs(keyword);
    }

    @Override
    public Result deleteEnv(String envName) {
        String fullPath = "/" + ConstantValues.ZK_ROOT_CONFIG_NAME + "/" + envName;
        try {
            zkNodeOperator.deleteNode(fullPath);
            return Result.ok();
        } catch (Exception e) {
            return Result.error("删除失败");
        }
    }

    @Override
    public Result saveEnv(String envName) {
        String fullPath = "/" + ConstantValues.ZK_ROOT_CONFIG_NAME + "/" + envName;
        try {
            if (!zkNodeOperator.existsNode(fullPath)) {
                zkNodeOperator.createNode(
                        fullPath,
                        NodeDataDTO.toBytes(new NodeDataDTO(fullPath, System.currentTimeMillis())));
            } else {
                return Result.error("节点已存在");
            }
            return Result.ok();
        } catch (Exception e) {
            return Result.error("创建失败");
        }
    }

    @Override
    public Result saveOrUpdateSpace(String envName, String spaceName) {
        String fullPath =
                "/" + ConstantValues.ZK_ROOT_CONFIG_NAME + "/" + envName + "/" + spaceName;
        try {
            if (!zkNodeOperator.existsNode(fullPath)) {
                zkNodeOperator.createNode(
                        fullPath,
                        NodeDataDTO.toBytes(new NodeDataDTO(fullPath, System.currentTimeMillis())));
                return Result.ok();
            } else {
                return Result.error("节点已存在");
            }
        } catch (Exception e) {
            return Result.error("创建失败");
        }
    }

    @Override
    public Result deleteSpace(String envName, String spaceName) {
        String fullPath =
                "/" + ConstantValues.ZK_ROOT_CONFIG_NAME + "/" + envName + "/" + spaceName;
        try {
            zkNodeOperator.deleteNode(fullPath);
            return Result.ok();
        } catch (Exception e) {
            return Result.error("删除失败");
        }
    }

    @Override
    public Result saveOrUpdateKey(
            String envName, String spaceName, String key, String value, String grayReleases) {
        String fullPath =
                "/"
                        + ConstantValues.ZK_ROOT_CONFIG_NAME
                        + "/"
                        + envName
                        + "/"
                        + spaceName
                        + "/"
                        + key;

        try {
            if (zkNodeOperator.existsNode(fullPath)) {
                byte[] nodeData = zkNodeOperator.getNodeData(fullPath);
                ConfigItemData itemData = new ConfigItemData();
                if (null != nodeData) {
                    itemData = ConfigItemData.from(nodeData);
                }
                itemData.setValue(value);
                itemData.setTs(System.currentTimeMillis());
                if (StringUtils.hasText(grayReleases)) {
                    List<String> releases =
                            Arrays.stream(grayReleases.split(",")).collect(Collectors.toList());
                    itemData.setGrayReleases(releases);
                } else {
                    itemData.setGrayReleases(new ArrayList<>());
                }
                zkNodeOperator.setNodeData(fullPath, ConfigItemData.toBytes(itemData));
            } else {
                ConfigItemData configItemData = new ConfigItemData();
                configItemData.setKey(key);
                configItemData.setValue(value);
                configItemData.setTs(System.currentTimeMillis());
                if (StringUtils.hasText(grayReleases)) {
                    List<String> releases =
                            Arrays.stream(grayReleases.split(",")).collect(Collectors.toList());
                    configItemData.setGrayReleases(releases);
                }
                zkNodeOperator.createNode(fullPath, ConfigItemData.toBytes(configItemData));
            }
        } catch (Exception e) {
            return Result.error("创建失败");
        }
        return Result.ok();
    }

    @Override
    public Result deleteKey(String envName, String spaceName, String key) {
        String fullPath =
                "/"
                        + ConstantValues.ZK_ROOT_CONFIG_NAME
                        + "/"
                        + envName
                        + "/"
                        + spaceName
                        + "/"
                        + key;
        try {
            zkNodeOperator.deleteNode(fullPath);
        } catch (Exception e) {
            return Result.error("删除失败");
        }
        return Result.ok();
    }

    @Override
    public List<ConfigVO> findAllKeys(String keyword, String envName, String spaceName) {
        return configContainer.findAllKeys(keyword, envName, spaceName);
    }

    @Override
    public ConfigItemData findConfigItemData(String envName, String spaceName, String key) {
        return configContainer.findConfigItemData(envName, spaceName, key);
    }

    @Override
    public List<String> findAllSpaces(String keyword, String envName) {
        return configContainer.findAllSpaces(keyword, envName);
    }

    @Override
    public List<String> findConfigSubscribeNodes(String envName, String spaceName) {
        return subscribeConfigContainer.findSubscribedHostInfos(envName, spaceName);
    }

    @Override
    public List<ConfigVO> configFuzzyQuery(String pattern) {
        return configContainer.configFuzzyQuery(pattern);
    }

    @Override
    public void copyToNewSpace(
            String oldEnvName, String oldSpaceName, String newEnvName, String newSpaceName) {
        String oldFullPath =
                "/" + ConstantValues.ZK_ROOT_CONFIG_NAME + "/" + oldEnvName + "/" + oldSpaceName;
        String newEnvFullPath = "/" + ConstantValues.ZK_ROOT_CONFIG_NAME + "/" + newEnvName;
        if (!zkNodeOperator.existsNode(newEnvFullPath)) {
            zkNodeOperator.createNode(
                    newEnvFullPath,
                    NodeDataDTO.toBytes(
                            new NodeDataDTO(newEnvFullPath, System.currentTimeMillis())));
        }
        String newSpaceFullPath = newEnvFullPath + "/" + newSpaceName;
        if (!zkNodeOperator.existsNode(newSpaceFullPath)) {
            zkNodeOperator.createNode(
                    newSpaceFullPath,
                    NodeDataDTO.toBytes(
                            new NodeDataDTO(newSpaceFullPath, System.currentTimeMillis())));
        }
        List<String> children = zkNodeOperator.getChildren(oldFullPath);
        for (String child : children) {
            byte[] nodeData = zkNodeOperator.getNodeData(oldFullPath + "/" + child);
            ConfigItemData configItemData = JsonUtils.fromJson(nodeData, ConfigItemData.class);
            configItemData.setTs(System.currentTimeMillis());
            configItemData.setGrayReleases(new ArrayList<>());
            String newChildFullPath = newSpaceFullPath + "/" + configItemData.getKey();
            if (!zkNodeOperator.existsNode(newChildFullPath)) {
                zkNodeOperator.createNode(newChildFullPath, ConfigItemData.toBytes(configItemData));
            } else {
                zkNodeOperator.setNodeData(
                        newChildFullPath, ConfigItemData.toBytes(configItemData));
            }
        }
    }

    @Override
    public void saveOrUpdateKeys(String envName, String spaceName, Map<String, String> configMap) {
        configMap.forEach(
                (key, value) -> {
                    String fullPath =
                            "/"
                                    + ConstantValues.ZK_ROOT_CONFIG_NAME
                                    + "/"
                                    + envName
                                    + "/"
                                    + spaceName
                                    + "/"
                                    + key;
                    ConfigItemData configItemData = new ConfigItemData();
                    configItemData.setGrayReleases(new ArrayList<>());
                    configItemData.setTs(System.currentTimeMillis());
                    configItemData.setKey(key);
                    configItemData.setValue(value);
                    if (!zkNodeOperator.existsNode(fullPath)) {
                        zkNodeOperator.createNode(fullPath, ConfigItemData.toBytes(configItemData));
                    } else {
                        zkNodeOperator.setNodeData(
                                fullPath, ConfigItemData.toBytes(configItemData));
                    }
                });
    }
}
